home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!cs.odu.edu!Amiga-Request
- From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
- Newsgroups: comp.sources.amiga
- Subject: v90i127: tar - tape archive utility, Part02/05
- Message-ID: <11980@xanth.cs.odu.edu>
- Date: 29 Mar 90 03:09:16 GMT
- Sender: tadguy@cs.odu.edu
- Reply-To: hue@netcom.uucp (Jonathan Hue)
- Lines: 1581
- Approved: tadguy@cs.odu.edu (Tad Guy)
- X-Mail-Submissions-To: Amiga@cs.odu.edu
- X-Post-Discussions-To: comp.sys.amiga
-
- Submitted-by: hue@netcom.uucp (Jonathan Hue)
- Posting-number: Volume 90, Issue 127
- Archive-name: unix/tar/part02
-
- #!/bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 5)."
- # Contents: list.c tar.1 tar.5 tar.c
- # Wrapped by tadguy@xanth on Wed Mar 28 22:07:12 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'list.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'list.c'\"
- else
- echo shar: Extracting \"'list.c'\" \(12340 characters\)
- sed "s/^X//" >'list.c' <<'END_OF_FILE'
- X/*
- X * List a tar archive.
- X *
- X * Also includes support routines for reading a tar archive.
- X *
- X * Pubic Domain version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
- X *
- X * @(#)list.c 1.31 11/5/87 Public Domain - gnu
- X */
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#if !defined(MSDOS) && !defined(AMIGA)
- X#include <sys/file.h>
- X#endif /* MSDOS */
- X
- X#ifdef USG
- X#include <sys/sysmacros.h> /* major() and minor() defined here */
- X#endif
- X
- Xchar *ctime(); /* From libc.a */
- X
- X#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
- X
- X#include "tar.h"
- X#include "port.h"
- X
- X#ifdef AMIGA
- Xint made_on_amiga; /* from extract.c */
- X#endif
- X
- Xlong from_oct(); /* Decode octal number */
- Xvoid demode(); /* Print file mode */
- X
- Xunion record *head; /* Points to current archive header */
- Xstruct stat hstat; /* Stat struct corresponding */
- Xint head_standard; /* Tape header is in ANSI format */
- X
- Xvoid print_header();
- Xvoid skip_file();
- X
- X
- X/*
- X * Main loop for reading an archive.
- X */
- Xvoid
- Xread_and(do_something)
- X void (*do_something)();
- X{
- X int status = 3; /* Initial status at start of archive */
- X int prev_status;
- X
- X name_gather(); /* Gather all the names */
- X open_archive(1); /* Open for reading */
- X
- X for(;;) {
- X prev_status = status;
- X status = read_header();
- X switch (status) {
- X
- X case 1: /* Valid header */
- X /* We should decode next field (mode) first... */
- X /* Ensure incoming names are null terminated. */
- X head->header.name[NAMSIZ-1] = '\0';
- X
- X if (!name_match(head->header.name)) {
- X /* Skip past it in the archive */
- X userec(head);
- X /* Skip to the next header on the archive */
- X skip_file((long)hstat.st_size);
- X continue;
- X }
- X
- X (*do_something)();
- X continue;
- X
- X /*
- X * If the previous header was good, tell them
- X * that we are skipping bad ones.
- X */
- X case 0: /* Invalid header */
- X userec(head);
- X switch (prev_status) {
- X case 3: /* Error on first record */
- X annorec(stderr, tar);
- X fprintf(stderr, "Hmm, this doesn't look like a tar archive.\n");
- X /* FALL THRU */
- X case 2: /* Error after record of zeroes */
- X case 1: /* Error after header rec */
- X annorec(stderr, tar);
- X fprintf(stderr,
- X "Skipping to next file header...\n");
- X case 0: /* Error after error */
- X break;
- X }
- X continue;
- X
- X case 2: /* Record of zeroes */
- X userec(head);
- X status = prev_status; /* If error after 0's */
- X if (f_ignorez)
- X continue;
- X /* FALL THRU */
- X case EOF: /* End of archive */
- X break;
- X }
- X break;
- X };
- X
- X close_archive();
- X names_notfound(); /* Print names not found */
- X}
- X
- X
- X/*
- X * Print a header record, based on tar options.
- X */
- Xvoid
- Xlist_archive()
- X{
- X
- X /* Save the record */
- X saverec(&head);
- X
- X /* Print the header record */
- X if (f_verbose) {
- X if (f_verbose > 1)
- X decode_header(head, &hstat, &head_standard, 0);
- X print_header(stdout);
- X }
- X
- X /* Skip past it in the archive */
- X saverec((union record **) 0); /* Unsave it */
- X userec(head);
- X
- X /* Skip to the next header on the archive */
- X skip_file((long)hstat.st_size);
- X}
- X
- X
- X/*
- X * Read a record that's supposed to be a header record.
- X * Return its address in "head", and if it is good, the file's
- X * size in hstat.st_size.
- X *
- X * Return 1 for success, 0 if the checksum is bad, EOF on eof,
- X * 2 for a record full of zeros (EOF marker).
- X *
- X * You must always userec(head) to skip past the header which this
- X * routine reads.
- X */
- Xint
- Xread_header()
- X{
- X register int i;
- X register long sum, recsum;
- X register char *p;
- X register union record *header;
- X
- X header = findrec();
- X head = header; /* This is our current header */
- X if (NULL == header) return EOF;
- X
- X recsum = from_oct(8, header->header.chksum);
- X
- X sum = 0;
- X p = header->charptr;
- X for (i = sizeof(*header); --i >= 0;) {
- X /*
- X * We can't use unsigned char here because of old compilers,
- X * e.g. V7.
- X */
- X sum += 0xFF & *p++;
- X }
- X
- X /* Adjust checksum to count the "chksum" field as blanks. */
- X for (i = sizeof(header->header.chksum); --i >= 0;)
- X sum -= 0xFF & header->header.chksum[i];
- X sum += ' '* sizeof header->header.chksum;
- X
- X if (sum == recsum) {
- X /*
- X * Good record. Decode file size and return.
- X */
- X if (header->header.linkflag == LF_LINK)
- X hstat.st_size = 0; /* Links 0 size on tape */
- X else
- X hstat.st_size = from_oct(1+12, header->header.size);
- X return 1;
- X }
- X
- X if (sum == 8*' ') {
- X /*
- X * This is a zeroed record...whole record is 0's except
- X * for the 8 blanks we faked for the checksum field.
- X */
- X return 2;
- X }
- X
- X return 0;
- X}
- X
- X
- X/*
- X * Decode things from a file header record into a "struct stat".
- X * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix
- X * Standard" tar format or regular old tar format.
- X *
- X * read_header() has already decoded the checksum and length, so we don't.
- X *
- X * If wantug != 0, we want the uid/group info decoded from Unix Standard
- X * tapes (for extraction). If == 0, we are just printing anyway, so save time.
- X *
- X * decode_header should NOT be called twice for the same record, since the
- X * two calls might use different "wantug" values and thus might end up with
- X * different uid/gid for the two calls. If anybody wants the uid/gid they
- X * should decode it first, and other callers should decode it without uid/gid
- X * before calling a routine, e.g. print_header, that assumes decoded data.
- X */
- Xdecode_header(header, st, stdp, wantug)
- X register union record *header;
- X register struct stat *st;
- X int *stdp;
- X int wantug;
- X{
- X made_on_amiga = FALSE;
- X st->st_mode = from_oct(8, header->header.mode);
- X st->st_mtime = from_oct(1+12, header->header.mtime);
- X#ifdef AMIGA
- X /*
- X * Tar file made on Amiga, use the prot and comment in header
- X */
- X if (!strcmp("AmigaTar", header->header.magic_cookie))
- X {
- X made_on_amiga = TRUE;
- X st->st_prot = from_hex(header->header.amiga_modes);
- X strcpy(st->st_comment, header->header.comment);
- X st->st_date.ds_Days = from_hex(header->header.ds_Days);
- X st->st_date.ds_Minute = from_hex(header->header.ds_Minute);
- X st->st_date.ds_Tick = from_hex(header->header.ds_Tick);
- X }
- X#endif
- X
- X if (0==strcmp(header->header.magic, TMAGIC)) {
- X /* Unix Standard tar archive */
- X *stdp = 1;
- X if (wantug) {
- X#ifdef NONAMES
- X st->st_uid = from_oct(8, header->header.uid);
- X st->st_gid = from_oct(8, header->header.gid);
- X#else
- X st->st_uid = finduid(header->header.uname);
- X st->st_gid = findgid(header->header.gname);
- X#endif
- X }
- X switch (header->header.linkflag)
- X case LF_BLK: case LF_CHR:
- X st->st_rdev = makedev(from_oct(8, header->header.devmajor),
- X from_oct(8, header->header.devminor));
- X } else {
- X /* Old fashioned tar archive */
- X *stdp = 0;
- X st->st_uid = from_oct(8, header->header.uid);
- X st->st_gid = from_oct(8, header->header.gid);
- X st->st_rdev = 0;
- X }
- X}
- X
- X
- X/*
- X * Quick and dirty octal conversion.
- X *
- X * Result is -1 if the field is invalid (all blank, or nonoctal).
- X */
- Xlong
- Xfrom_oct(digs, where)
- X register int digs;
- X register char *where;
- X{
- X register long value;
- X
- X while (isspace(*where)) { /* Skip spaces */
- X where++;
- X if (--digs <= 0)
- X return -1; /* All blank field */
- X }
- X value = 0;
- X while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
- X value = (value << 3) | (*where++ - '0');
- X --digs;
- X }
- X
- X if (digs > 0 && *where && !isspace(*where))
- X return -1; /* Ended on non-space/nul */
- X
- X return value;
- X}
- X
- X
- X/*
- X * Actually print it.
- X *
- X * Plain and fancy file header block logging.
- X * Non-verbose just prints the name, e.g. for "tar t" or "tar x".
- X * This should just contain file names, so it can be fed back into tar
- X * with xargs or the "-T" option. The verbose option can give a bunch
- X * of info, one line per file. I doubt anybody tries to parse its
- X * format, or if they do, they shouldn't. Unix tar is pretty random here
- X * anyway.
- X *
- X * Note that print_header uses the globals <head>, <hstat>, and
- X * <head_standard>, which must be set up in advance. This is not very clean
- X * and should be cleaned up. FIXME.
- X */
- X#define UGSWIDTH 11 /* min width of User, group, size */
- X#define DATEWIDTH 19 /* Last mod date */
- Xstatic int ugswidth = UGSWIDTH; /* Max width encountered so far */
- X
- Xvoid
- Xprint_header(outfile)
- X FILE *outfile;
- X{
- X char modes[11];
- X char *timestamp;
- X char uform[11], gform[11]; /* These hold formatted ints */
- X char *user, *group;
- X char size[24]; /* Holds a formatted long or maj, min */
- X long longie; /* To make ctime() call portable */
- X int pad;
- X
- X annofile(outfile, (char *)NULL);
- X
- X if (f_verbose <= 1) {
- X /* Just the fax, mam. */
- X fprintf(outfile, "%s\n", head->header.name);
- X return;
- X } else {
- X /* File type and modes */
- X modes[0] = '?';
- X switch (head->header.linkflag) {
- X case LF_NORMAL:
- X case LF_OLDNORMAL:
- X case LF_LINK:
- X modes[0] = '-';
- X if ('/' == head->header.name[strlen(head->header.name)-1])
- X modes[0] = 'd';
- X break;
- X case LF_DIR: modes[0] = 'd'; break;
- X case LF_SYMLINK:modes[0] = 'l'; break;
- X case LF_BLK: modes[0] = 'b'; break;
- X case LF_CHR: modes[0] = 'c'; break;
- X case LF_FIFO: modes[0] = 'p'; break;
- X case LF_CONTIG: modes[0] = 'C'; break;
- X }
- X
- X demode((unsigned)hstat.st_mode, modes+1);
- X
- X /* Timestamp */
- X longie = hstat.st_mtime;
- X timestamp = ctime(&longie);
- X timestamp[16] = '\0';
- X timestamp[24] = '\0';
- X
- X /* User and group names */
- X if (*head->header.uname && head_standard) {
- X user = head->header.uname;
- X } else {
- X user = uform;
- X (void)sprintf(uform, "%d", (int)hstat.st_uid);
- X }
- X if (*head->header.gname && head_standard) {
- X group = head->header.gname;
- X } else {
- X group = gform;
- X (void)sprintf(gform, "%d", (int)hstat.st_gid);
- X }
- X
- X /* Format the file size or major/minor device numbers */
- X switch (head->header.linkflag) {
- X case LF_CHR:
- X case LF_BLK:
- X (void)sprintf(size, "%d,%d",
- X major(hstat.st_rdev),
- X minor(hstat.st_rdev));
- X break;
- X
- X default:
- X (void)sprintf(size, "%ld", (long)hstat.st_size);
- X }
- X
- X /* Figure out padding and print the whole line. */
- X pad = strlen(user) + strlen(group) + strlen(size) + 1;
- X if (pad > ugswidth) ugswidth = pad;
- X
- X fprintf(outfile, "%s %s/%s %*s%s %s %s %.*s",
- X modes,
- X user,
- X group,
- X ugswidth - pad,
- X "",
- X size,
- X timestamp+4, timestamp+20,
- X sizeof(head->header.name),
- X head->header.name);
- X
- X switch (head->header.linkflag) {
- X case LF_SYMLINK:
- X fprintf(outfile, " -> %s\n", head->header.linkname);
- X break;
- X
- X case LF_LINK:
- X fprintf(outfile, " link to %s\n", head->header.linkname);
- X break;
- X
- X default:
- X fprintf(outfile, " unknown file type '%c'\n",
- X head->header.linkflag);
- X break;
- X
- X case LF_OLDNORMAL:
- X case LF_NORMAL:
- X case LF_CHR:
- X case LF_BLK:
- X case LF_DIR:
- X case LF_FIFO:
- X case LF_CONTIG:
- X putc('\n', outfile);
- X break;
- X }
- X }
- X}
- X
- X/*
- X * Print a similar line when we make a directory automatically.
- X */
- Xvoid
- Xpr_mkdir(pathname, length, mode, outfile)
- X char *pathname;
- X int length;
- X int mode;
- X FILE *outfile;
- X{
- X char modes[11];
- X
- X if (f_verbose > 1) {
- X /* File type and modes */
- X modes[0] = 'd';
- X demode((unsigned)mode, modes+1);
- X
- X annofile(outfile, (char *)NULL);
- X fprintf(outfile, "%s %*s %.*s\n",
- X modes,
- X ugswidth+DATEWIDTH,
- X "Creating directory:",
- X length,
- X pathname);
- X }
- X}
- X
- X
- X/*
- X * Skip over <size> bytes of data in records in the archive.
- X */
- Xvoid
- Xskip_file(size)
- X register long size;
- X{
- X union record *x;
- X
- X while (size > 0) {
- X x = findrec();
- X if (x == NULL) { /* Check it... */
- X annorec(stderr, tar);
- X fprintf(stderr, "Unexpected EOF on archive file\n");
- X exit(EX_BADARCH);
- X }
- X userec(x);
- X size -= RECORDSIZE;
- X }
- X}
- X
- X
- X/*
- X * Decode the mode string from a stat entry into a 9-char string and a null.
- X */
- Xvoid
- Xdemode(mode, string)
- X register unsigned mode;
- X register char *string;
- X{
- X register unsigned mask;
- X register char *rwx = "rwxrwxrwx";
- X
- X for (mask = 0400; mask != 0; mask >>= 1) {
- X if (mode & mask)
- X *string++ = *rwx++;
- X else {
- X *string++ = '-';
- X rwx++;
- X }
- X }
- X
- X if (mode & S_ISUID)
- X if (string[-7] == 'x')
- X string[-7] = 's';
- X else
- X string[-7] = 'S';
- X if (mode & S_ISGID)
- X if (string[-4] == 'x')
- X string[-4] = 's';
- X else
- X string[-4] = 'S';
- X if (mode & S_ISVTX)
- X if (string[-1] == 'x')
- X string[-1] = 't';
- X else
- X string[-1] = 'T';
- X *string = '\0';
- X}
- X
- X#ifdef AMIGA
- Xfrom_hex(char *s)
- X{
- X int i, val = 0;
- X char nibble;
- X
- X for (i = 0; i < 8; i++)
- X {
- X nibble = *s++;
- X nibble = (nibble >= 'a') ? 10 + (nibble - 'a') : nibble - '0';
- X val = (val << 4) + nibble;
- X }
- X return(val);
- X}
- X#endif
- END_OF_FILE
- if test 12340 -ne `wc -c <'list.c'`; then
- echo shar: \"'list.c'\" unpacked with wrong size!
- fi
- # end of 'list.c'
- fi
- if test -f 'tar.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tar.1'\"
- else
- echo shar: Extracting \"'tar.1'\" \(10973 characters\)
- sed "s/^X//" >'tar.1' <<'END_OF_FILE'
- X.TH TAR 1 "5 November 1987"
- X.\" @(#)tar.1 1.12 11/6/87 Public Domain - gnu
- X.SH NAME
- Xtar \- tape (or other media) file archiver
- X.SH SYNOPSIS
- X\fBtar\fP \-[\fBBcdDhiklmopRstvxzZ\fP]
- X[\fB\-b\fP \fIN\fP]
- X[\fB\-f\fP \fIF\fP]
- X[\fB\-T\fP \fIF\fP]
- X[ \fIfilename or regexp\fP\| .\|.\|. ]
- X.SH DESCRIPTION
- X\fItar\fP provides a way to store many files into a single archive,
- Xwhich can be kept in another Unix file, stored on an I/O device
- Xsuch as tape, floppy, cartridge, or disk, sent over a network, or piped to
- Xanother program.
- XIt is useful for making backup copies, or for packaging up a set of
- Xfiles to move them to another system.
- X.LP
- X\fItar\fP has existed since Version 7 Unix with very little change.
- XIt has been proposed as the standard format for interchange of files
- Xamong systems that conform to the IEEE P1003 ``Portable Operating System''
- Xstandard.
- X.LP
- XThis version of \fItar\fP supports some of the extensions which
- Xwere proposed in the P1003 draft standards, including owner and group
- Xnames, and support for named pipes, fifos, contiguous files,
- Xand block and character devices.
- X.LP
- XWhen reading an archive, this version of \fItar\fP continues after
- Xfinding an error. Previous versions required the `i' option to ignore
- Xchecksum errors.
- X.SH OPTIONS
- X\fItar\fP options can be specified in either of two ways. The usual
- XUnix conventions can be used: each option is preceded by `\-'; arguments
- Xdirectly follow each option; multiple options can be combined behind one `\-'
- Xas long as they take no arguments. For compatability with the Unix
- X\fItar\fP program, the options may also be specified as ``keyletters,''
- Xwherein all the option letters occur in the first argument to \fItar\fP,
- Xwith no `\-', and their arguments, if any, occur in the second, third, ...
- Xarguments. Examples:
- X.LP
- XNormal: tar -f arcname -cv file1 file2
- X.LP
- XOld: tar fcv arcname file1 file2
- X.LP
- XAt least one of the \fB\-c\fP, \fB\-t\fP, \fB-d\fP, or \fB\-x\fP options
- Xmust be included. The rest are optional.
- X.LP
- XFiles to be operated upon are specified by a list of file names, which
- Xfollows the option specifications (or can be read from a file by the
- X\fB\-T\fP option). Specifying a directory name causes that directory
- Xand all the files it contains to be (recursively) processed. If a
- Xfull path name is specified when creating an archive, it will be written
- Xto the archive without the initial "/", to allow the files to be later
- Xread into a different place than where they were
- Xdumped from, and a warning will be printed. If
- Xfiles are extracted from an archive which contains
- Xfull path names, they will be extracted relative to the current directory
- Xand a warning message printed.
- X.LP
- XWhen extracting or listing files, the ``file names'' are treated as
- Xregular expressions, using mostly the same syntax as the shell. The
- Xshell actually matches each substring between ``/''s separately, while
- X\fItar\fP matches the entire string at once, so some anomalies will
- Xoccur; e.g. ``*'' or ``?'' can match a ``/''. To specify a regular
- Xexpression as an argument to \fItar\fP, quote it so the shell will not
- Xexpand it.
- X.IP \fB\-a\fP
- XSet the archived bit of the file as it is added to the archive. (Amiga
- Xonly)
- X.IP \fB\-A\fP
- XDo not add the file to the archive if its archived bit is set.
- XApplies only to regular files, directories are always dumped
- X(Amiga only)
- X.IP "\fB\-b\fP \fIN\fP"
- XSpecify a blocking factor for the archive. The block size will be
- X\fIN\fP x 512 bytes. Larger blocks typically run faster and let you
- Xfit more data on a tape. The default blocking factor is set when
- X\fItar\fP is compiled, and is typically 20. There is no limit to the
- Xmaximum block size, as long as enough memory can be allocated for it,
- Xand as long as the device containing the archive can read or write
- Xthat block size.
- X.IP \fB\-B\fP
- XWhen reading an archive, reblock it as we read it.
- XNormally, \fItar\fP reads each
- Xblock with a single \fIread(2)\fP system call. This does not work
- Xwhen reading from a pipe or network socket under Berkeley Unix;
- X\fIread(2)\fP only gives as much data as has arrived at the moment.
- XWith this option, it
- Xwill do multiple \fIread(2)\fPs to fill out to a record boundary,
- Xrather than reporting an error.
- XThis option is default when reading an archive from standard input,
- Xor over a network.
- X.IP \fB\-c\fP
- XCreate an archive from a list of files.
- X.IP \fB\-d\fP
- XDiff an archive against the files in the file system. Reports
- Xdifferences in file size, mode, uid, gid, and contents. If a file
- Xexists on the tape, but not in the file system, that is reported.
- XThis option needs further work to be really useful.
- X.IP \fB\-D\fP
- XWhen creating an archive, only dump each directory itself; don't dump
- Xall the files inside the directory. In conjunction with \fIfind\fP(1),
- Xthis is useful in creating incremental dumps for archival backups,
- Xsimilar to those produced by \fIdump\fP(8).
- X.IP "\fB\-f\fP \fIF\fP"
- XSpecify the filename of the archive. If the specified filename is ``\-'',
- Xthe archive is read from the standard input or written to the standard output.
- XIf the \fB-f\fP option is not used, and the environment variable \fBTAPE\fP
- Xexists, its value will be used; otherwise,
- Xa default archive name (which was picked when tar was compiled) is used.
- XThe default is normally set to the ``first'' tape drive or other transportable
- XI/O medium on the system.
- X.IP
- XIf the filename contains a colon before a slash, it is interpreted
- Xas a ``hostname:/file/name'' pair. \fItar\fP will invoke the commands
- X\fIrsh\fP and \fIdd\fP to access the specified file or device on the
- Xsystem \fIhostname\fP. If you need to do something unusual like rsh with
- Xa different user name, use ``\fB\-f \-\fP'' and pipe it to rsh manually.
- X.IP \fB\-h\fP
- XWhen creating an archive, if a symbolic link is encountered, dump
- Xthe file or directory to which it points, rather than
- Xdumping it as a symbolic link. (Does not apply to Amiga)
- X.IP \fB\-i\fP
- XWhen reading an archive, ignore blocks of zeros in the archive. Normally
- Xa block of zeros indicates the end of the archive,
- Xbut in a damaged archive, or one which was
- Xcreated by appending several archives, this option allows \fItar\fP to
- Xcontinue. It is not on by default because there is garbage written after the
- Xzeroed blocks by the Unix \fItar\fP program. Note that with this option
- Xset, \fItar\fP will read all the way to the end of the file, eliminating
- Xproblems with multi-file tapes.
- X.IP \fB\-k\fP
- XWhen extracting files from an archive, keep existing files, rather than
- Xoverwriting them with the version from the archive.
- X.IP \fB\-l\fP
- XWhen dumping the contents of a directory to an archive, stay within the
- Xlocal file system of that directory. This option
- Xonly affects the files dumped because
- Xthey are in a dumped directory; files named on the command line are
- Xalways dumped, and they can be from various file systems.
- XThis is useful for making ``full dump'' archival backups of a file system,
- Xas with the \fIdump\fP(8) command. Files which are skipped due to this
- Xoption are mentioned on the standard error.
- X.IP \fB\-m\fP
- XWhen extracting files from an archive, set each file's modified timestamp
- Xto the current time, rather than extracting each file's modified
- Xtimestamp from the archive.
- X.IP \fB\-o\fP
- XWhen creating an archive, write an old format archive, which does not
- Xinclude information about directories, pipes, fifos,
- Xcontiguous files, or device files, and
- Xspecifies file ownership by uid's and gid's rather than by
- Xuser names and group names. In most cases, a ``new'' format archive
- Xcan be read by an ``old'' tar program without serious trouble, so this
- Xoption should seldom be needed.
- X.IP \fB\-p\fP
- XWhen extracting files from an archive, restore them to the same permissions
- Xthat they had in the archive. If \fB\-p\fP is not specified, the current
- Xumask limits the permissions of the extracted files. See \fIumask(2)\fP.
- X(Does not apply to Amiga version, permission always completely restored)
- X.IP \fB\-R\fP
- XWith each message that \fItar\fP produces, print the record number
- Xwithin the archive where the message occurred. This option is especially
- Xuseful when reading damaged archives, since it helps to pinpoint the damaged
- Xsection.
- X.IP \fB\-s\fP
- XWhen specifying a list of filenames to be listed
- Xor extracted from an archive,
- Xthe \fB\-s\fP flag specifies that the list
- Xis sorted into the same order as the tape. This allows a large list
- Xto be used, even on small machines, because
- Xthe entire list need not be read into memory at once. Such a sorted
- Xlist can easily be created by running ``tar \-t'' on the archive and
- Xediting its output.
- X.IP \fB\-t\fP
- XList a table of contents of an existing archive. If file names are
- Xspecified, just list files matching the specified names. The listing
- Xappears on the standard output.
- X.IP "\fB\-T\fP \fIF\fP"
- XRather than specifying file names or regular expressions as arguments to
- Xthe \fItar\fP command, this option specifies that they should
- Xbe read from the file \fIF\fP, one per line.
- XIf the file name specified is ``\-'',
- Xthe list is read from the standard input.
- XThis option, in conjunction with the \fB\-s\fP option,
- Xallows an arbitrarily large list of files to be processed,
- Xand allows the list to be piped to \fItar\fP.
- X.IP \fB\-v\fP
- XBe verbose about the files that are being processed or listed. Normally,
- Xarchive creation, file extraction, and differencing are silent,
- Xand archive listing just
- Xgives file names. The \fB\-v\fP option causes an ``ls \-l''\-like listing
- Xto be produced. The output from -v appears on the standard output except
- Xwhen creating an archive (since the new archive might be on standard output),
- Xwhere it goes to the standard error output.
- X.IP \fB\-x\fP
- XExtract files from an existing archive. If file names are
- Xspecified, just extract files matching the specified names, otherwise extract
- Xall the files in the archive.
- X.IP "\fB\-z\fP or \fB\-Z\fP"
- XThe archive should be compressed as it is written, or decompressed as it
- Xis read, using the \fIcompress(1)\fP program. This option works on I/O
- Xdevices and over the network, as well as on disk files; data to or from
- Xsuch devices is reblocked using a ``dd'' command
- Xto enforce the specified (or default) block size. The default compression
- Xparameters are used; if you need to override them, avoid the ``z'' option
- Xand compress it yourself. (Not currently supported on Amiga)
- X.SH "SEE ALSO"
- Xshar(1), tar(5), compress(1), ar(1), arc(1), cpio(1), dump(8), restore(8),
- Xrestor(8), rsh(1), dd(1), find(1)
- X.SH BUGS
- XThe \fBr, u, w, X, l, F, C\fP, and \fIdigit\fP options of Unix \fItar\fP
- Xare not supported.
- X.LP
- XMultiple-tape (or floppy) archives should be supported, but so far no
- Xclean way has been implemented.
- X.LP
- XA bug in the Bourne Shell usually causes an extra newline to be written
- Xto the standard error when using compressed or remote archives.
- X.LP
- XA bug in ``dd'' prevents turning off the ``x+y records in/out'' messages
- Xon the standard error when ``dd'' is used to reblock or transport an archive.
- END_OF_FILE
- if test 10973 -ne `wc -c <'tar.1'`; then
- echo shar: \"'tar.1'\" unpacked with wrong size!
- fi
- # end of 'tar.1'
- fi
- if test -f 'tar.5' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tar.5'\"
- else
- echo shar: Extracting \"'tar.5'\" \(9253 characters\)
- sed "s/^X//" >'tar.5' <<'END_OF_FILE'
- X.TH TAR 5 "15 October 1987"
- X.\" @(#)tar.5 1.4 11/6/87 Public Domain - gnu
- X.SH NAME
- Xtar \- tape (or other media) archive file format
- X.SH DESCRIPTION
- XA ``tar tape'' or file contains a series of records. Each record contains
- XTRECORDSIZE bytes (see below). Although this format may be thought of as
- Xbeing on magnetic tape, other media are often used.
- XEach file archived is represented by a header record
- Xwhich describes the file, followed by zero or more records which give the
- Xcontents of the file. At the end of the archive file there may be a record
- Xfilled with binary zeros as an end-of-file indicator. A reasonable
- Xsystem should write a record of zeros at the end, but must not assume that
- Xan end-of-file record exists when reading an archive.
- X
- XThe records may be blocked for physical I/O operations. Each block of
- X\fIN\fP records (where \fIN\fP is set by the \fB\-b\fP option to \fItar\fP)
- Xis written with a single write() operation. On
- Xmagnetic tapes, the result of such a write is a single tape record.
- XWhen writing an archive, the last block of records should be written
- Xat the full size, with records after the zero record containing
- Xall zeroes. When reading an archive, a reasonable system should
- Xproperly handle an archive whose last block is shorter than the rest, or
- Xwhich contains garbage records after a zero record.
- X
- XThe header record is defined in the header file <tar.h> as follows:
- X.nf
- X.sp .5v
- X.DT
- X/*
- X * Standard Archive Format - Standard TAR - USTAR
- X */
- X#define RECORDSIZE 512
- X#define NAMSIZ 100
- X#define TUNMLEN 32
- X#define TGNMLEN 32
- X
- Xunion record {
- X char charptr[RECORDSIZE];
- X struct header {
- X char name[NAMSIZ];
- X char mode[8];
- X char uid[8];
- X char gid[8];
- X char size[12];
- X char mtime[12];
- X char chksum[8];
- X char linkflag;
- X char linkname[NAMSIZ];
- X char magic[8];
- X char uname[TUNMLEN];
- X char gname[TGNMLEN];
- X char devmajor[8];
- X char devminor[8];
- X } header;
- X};
- X
- X/* The checksum field is filled with this while the checksum is computed. */
- X#define CHKBLANKS " " /* 8 blanks, no null */
- X
- X/* The magic field is filled with this if uname and gname are valid. */
- X#define TMAGIC "ustar " /* 7 chars and a null */
- X
- X/* The linkflag defines the type of file */
- X#define LF_OLDNORMAL '\\0' /* Normal disk file, Unix compatible */
- X#define LF_NORMAL '0' /* Normal disk file */
- X#define LF_LINK '1' /* Link to previously dumped file */
- X#define LF_SYMLINK '2' /* Symbolic link */
- X#define LF_CHR '3' /* Character special file */
- X#define LF_BLK '4' /* Block special file */
- X#define LF_DIR '5' /* Directory */
- X#define LF_FIFO '6' /* FIFO special file */
- X#define LF_CONTIG '7' /* Contiguous file */
- X/* Further link types may be defined later. */
- X
- X/* Bits used in the mode field - values in octal */
- X#define TSUID 04000 /* Set UID on execution */
- X#define TSGID 02000 /* Set GID on execution */
- X#define TSVTX 01000 /* Save text (sticky bit) */
- X
- X/* File permissions */
- X#define TUREAD 00400 /* read by owner */
- X#define TUWRITE 00200 /* write by owner */
- X#define TUEXEC 00100 /* execute/search by owner */
- X#define TGREAD 00040 /* read by group */
- X#define TGWRITE 00020 /* write by group */
- X#define TGEXEC 00010 /* execute/search by group */
- X#define TOREAD 00004 /* read by other */
- X#define TOWRITE 00002 /* write by other */
- X#define TOEXEC 00001 /* execute/search by other */
- X.fi
- X.LP
- XAll characters in header records
- Xare represented using 8-bit characters in the local
- Xvariant of ASCII.
- XEach field within the structure is contiguous; that is, there is
- Xno padding used within the structure. Each character on the archive medium
- Xis stored contiguously.
- X
- XBytes representing the contents of files (after the header record
- Xof each file) are not translated in any way and
- Xare not constrained to represent characters or to be in any character set.
- XThe \fItar\fP(5) format does not distinguish text files from binary
- Xfiles, and no translation of file contents should be performed.
- X
- XThe fields \fIname, linkname, magic, uname\fP, and \fIgname\fP are
- Xnull-terminated
- Xcharacter strings. All other fields are zero-filled octal numbers in
- XASCII. Each numeric field (of width \fIw\fP) contains \fIw\fP-2 digits, a space, and
- Xa null, except \fIsize\fP and \fImtime\fP,
- Xwhich do not contain the trailing null.
- X
- XThe \fIname\fP field is the pathname of the file, with directory names
- X(if any) preceding the file name, separated by slashes.
- X
- XThe \fImode\fP field provides nine bits specifying file permissions and three
- Xbits to specify the Set UID, Set GID and Save Text (TSVTX) modes. Values
- Xfor these bits are defined above. When special permissions are required
- Xto create a file with a given mode, and the user restoring files from the
- Xarchive does not hold such permissions, the mode bit(s) specifying those
- Xspecial permissions are ignored. Modes which are not supported by the
- Xoperating system restoring files from the archive will be ignored.
- XUnsupported modes should be faked up when creating an archive; e.g.
- Xthe group permission could be copied from the `other' permission.
- X
- XThe \fIuid\fP and \fIgid\fP fields are the user and group ID of the file owners,
- Xrespectively.
- X
- XThe \fIsize\fP field is the size of the file in bytes; linked files are archived
- Xwith this field specified as zero.
- X
- XThe \fImtime\fP field is the modification time of the file at the time it was
- Xarchived. It is the ASCII representation of the octal value of the
- Xlast time the file was modified, represented as in integer number of
- Xseconds since January 1, 1970, 00:00 Coordinated Universal Time.
- X
- XThe \fIchksum\fP field is the ASCII representaion of the octal value of the
- Xsimple sum of all bytes in the header record. Each 8-bit byte in the
- Xheader is treated as an unsigned value. These values are added to an
- Xunsigned integer, initialized to zero, the precision of which shall be no
- Xless than seventeen bits. When calculating the checksum, the \fIchksum\fP
- Xfield is treated as if it were all blanks.
- X
- XThe \fItypeflag\fP field specifies the type of file archived. If a particular
- Ximplementation does not recognize or permit the specified type, the file
- Xwill be extracted as if it were a regular file. As this action occurs,
- X\fItar\fP issues a warning to the standard error.
- X.IP "LF_NORMAL or LF_OLDNORMAL"
- Xrepresents a regular file.
- XFor backward compatibility, a \fItypeflag\fP value of LF_OLDNORMAL
- Xshould be silently recognized as a regular file. New archives should
- Xbe created using LF_NORMAL.
- XAlso, for backward
- Xcompatability, \fItar\fP treats a regular file whose name ends
- Xwith a slash as a directory.
- X.IP LF_LINK
- Xrepresents a file linked to another file, of any type,
- Xpreviously archived. Such files are identified in Unix by each file
- Xhaving the same device and inode number. The linked-to
- Xname is specified in the \fIlinkname\fP field with a trailing null.
- X.IP LF_SYMLINK
- Xrepresents a symbolic link to another file. The linked-to
- Xname is specified in the \fIlinkname\fP field with a trailing null.
- X.IP "LF_CHR or LF_BLK"
- Xrepresent character special files and block
- Xspecial files respectively.
- XIn this case the \fIdevmajor\fP and \fIdevminor\fP
- Xfields will contain the
- Xmajor and minor device numbers respectively. Operating
- Xsystems may map the device specifications to their own local
- Xspecification, or may ignore the entry.
- X.IP LF_DIR
- Xspecifies a directory or sub-directory. The directory name
- Xin the \fIname\fP field should end with a slash.
- XOn systems where
- Xdisk allocation is performed on a directory basis the \fIsize\fP
- Xfield will contain the maximum number of bytes (which may be
- Xrounded to the nearest disk block allocation unit) which the
- Xdirectory may hold. A \fIsize\fP field of zero indicates no such
- Xlimiting. Systems which do not support limiting in this
- Xmanner should ignore the \fIsize\fP field.
- X.IP LF_FIFO
- Xspecifies a FIFO special file. Note that the archiving of
- Xa FIFO file archives the existence of this file and not its
- Xcontents.
- X.IP LF_CONTIG
- Xspecifies a contiguous file, which is the same as a normal
- Xfile except that, in operating systems which support it,
- Xall its space is allocated contiguously on the disk. Operating
- Xsystems which do not allow contiguous allocation should silently treat
- Xthis type as a normal file.
- X.IP "`A' \- `Z'"
- Xare reserved for custom implementations. None are used by this
- Xversion of the \fItar\fP program.
- X.IP \fIother\fP
- Xvalues are reserved for specification in future revisions of the
- XP1003 standard, and should not be used by any \fItar\fP program.
- X.LP
- XThe \fImagic\fP field indicates that this archive was output in the P1003
- Xarchive format. If this field contains TMAGIC, then the
- X\fIuname\fP and \fIgname\fP
- Xfields will contain the ASCII representation of the owner and group of the
- Xfile respectively. If found, the user and group ID represented by these
- Xnames
- Xwill be used rather than the values contained
- Xwithin the \fIuid\fP and \fIgid\fP fields.
- XUser names longer than TUNMLEN-1 or group
- Xnames longer than TGNMLEN-1 characters will be truncated.
- X.SH "SEE ALSO"
- Xtar(1), ar(5), cpio(5), dump(8), restor(8), restore(8)
- X.SH BUGS
- XNames or link names longer than NAMSIZ-1 characters cannot be archived.
- X
- XThis format does not yet address multi-volume archives.
- X.SH NOTES
- XThis manual page was adapted by John Gilmore
- Xfrom Draft 6 of the P1003 specification
- END_OF_FILE
- if test 9253 -ne `wc -c <'tar.5'`; then
- echo shar: \"'tar.5'\" unpacked with wrong size!
- fi
- # end of 'tar.5'
- fi
- if test -f 'tar.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tar.c'\"
- else
- echo shar: Extracting \"'tar.c'\" \(11897 characters\)
- sed "s/^X//" >'tar.c' <<'END_OF_FILE'
- X/*
- X * A public domain tar(1) program.
- X *
- X * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
- X *
- X * @(#)tar.c 1.34 11/6/87 Public Domain - gnu
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h> /* Needed for typedefs in tar.h */
- X
- Xextern char *malloc();
- Xextern char *getenv();
- Xextern char *strncpy();
- Xextern char *optarg; /* Pointer to argument */
- Xextern int optind; /* Global argv index from getopt */
- X
- X/*
- X * The following causes "tar.h" to produce definitions of all the
- X * global variables, rather than just "extern" declarations of them.
- X */
- X#define TAR_EXTERN /**/
- X#include "tar.h"
- X
- X/*
- X * We should use a conversion routine that does reasonable error
- X * checking -- atoi doesn't. For now, punt. FIXME.
- X */
- X#define intconv atoi
- Xextern int getoldopt();
- Xextern void read_and();
- Xextern void list_archive();
- Xextern void extract_archive();
- Xextern void diff_archive();
- Xextern void create_archive();
- X
- Xstatic FILE *namef; /* File to read names from */
- Xstatic char **n_argv; /* Argv used by name routines */
- Xstatic int n_argc; /* Argc used by name routines */
- X /* They also use "optind" from getopt(). */
- X
- Xvoid describe();
- X
- X#ifdef AMIGA
- Xextern char *_TZ; /* timezone stuff */
- X#endif
- X
- X/*
- X * Main routine for tar.
- X */
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X
- X /* Uncomment this message in particularly buggy versions...
- X fprintf(stderr,
- X "tar: You are running an experimental PD tar, maybe use /bin/tar.\n");
- X */
- X
- X tar = "tar"; /* Set program name */
- X
- X options(argc, argv);
- X
- X name_init(argc, argv);
- X
- X if (f_create) {
- X if (f_extract || f_list || f_diff) goto dupflags;
- X create_archive();
- X } else if (f_extract) {
- X if (f_list || f_diff) goto dupflags;
- X extr_init();
- X read_and(extract_archive);
- X } else if (f_list) {
- X if (f_diff) goto dupflags;
- X read_and(list_archive);
- X } else if (f_diff) {
- X diff_init();
- X read_and(diff_archive);
- X } else {
- Xdupflags:
- X fprintf (stderr,
- X"tar: you must specify exactly one of the c, t, x, or d options\n");
- X describe();
- X exit(EX_ARGSBAD);
- X }
- X exit(0);
- X /* NOTREACHED */
- X}
- X
- X
- X/*
- X * Parse the options for tar.
- X */
- Xint
- Xoptions(argc, argv)
- X int argc;
- X char **argv;
- X{
- X register int c; /* Option letter */
- X#ifdef AMIGA
- X char *timezone;
- X#endif
- X
- X /* Set default option values */
- X blocking = DEFBLOCKING; /* From Makefile */
- X ar_file = getenv("TAPE"); /* From environment, or */
- X#ifdef AMIGA
- X timezone = getenv("TZ");
- X if (timezone)
- X {
- X _TZ = malloc(strlen(timezone) + 1); /* man page unclear about */
- X strcpy(_TZ, timezone); /* whether this is needed */
- X free(timezone);
- X }
- X else
- X _TZ = "CST6CDT";
- X tzset();
- X#endif
- X if (ar_file == 0)
- X#ifdef AMIGA
- X ar_file = "ram:tarfile"; /* From Makefile */
- X#else
- X ar_file = DEF_AR_FILE; /* From Makefile */
- X#endif
- X /* Parse options */
- X#ifdef AMIGA
- X while ((c = getoldopt(argc, argv, "aAb:BcdDf:hiklmopRstT:vxzZ")
- X#else
- X while ((c = getoldopt(argc, argv, "b:BcdDf:hiklmopRstT:vxzZ")
- X#endif
- X ) != EOF) {
- X switch (c) {
- X
- X#ifdef AMIGA
- X case 'a':
- X f_archive_set++;
- X break;
- X
- X case 'A':
- X f_archive_check++;
- X break;
- X#endif
- X
- X case 'b':
- X blocking = intconv(optarg);
- X break;
- X
- X case 'B':
- X f_reblock++; /* For reading 4.2BSD pipes */
- X break;
- X
- X case 'c':
- X f_create++;
- X break;
- X
- X case 'd':
- X f_diff++; /* Find difference tape/disk */
- X break;
- X
- X case 'D':
- X f_dironly++; /* Dump dir, not contents */
- X break;
- X
- X case 'f':
- X ar_file = optarg;
- X break;
- X
- X case 'h':
- X f_follow_links++; /* follow symbolic links */
- X break;
- X
- X case 'i':
- X f_ignorez++; /* Ignore zero records (eofs) */
- X /*
- X * This can't be the default, because Unix tar
- X * writes two records of zeros, then pads out the
- X * block with garbage.
- X */
- X break;
- X
- X case 'k': /* Don't overwrite files */
- X#ifdef NO_OPEN3
- X fprintf(stderr,
- X "tar: can't do -k option on this system\n");
- X exit(EX_ARGSBAD);
- X#else
- X f_keep++;
- X#endif
- X break;
- X
- X case 'l':
- X f_local_filesys++;
- X break;
- X
- X case 'm':
- X f_modified++;
- X break;
- X
- X case 'o': /* Generate old archive */
- X f_oldarch++;
- X break;
- X
- X case 'p':
- X f_use_protection++;
- X break;
- X
- X case 'R':
- X f_sayblock++; /* Print block #s for debug */
- X break; /* of bad tar archives */
- X
- X case 's':
- X f_sorted_names++; /* Names to extr are sorted */
- X break;
- X
- X case 't':
- X f_list++;
- X f_verbose++; /* "t" output == "cv" or "xv" */
- X break;
- X
- X case 'T':
- X name_file = optarg;
- X f_namefile++;
- X break;
- X
- X case 'v':
- X f_verbose++;
- X break;
- X
- X case 'x':
- X f_extract++;
- X break;
- X
- X case 'z': /* Easy to type */
- X case 'Z': /* Like the filename extension .Z */
- X f_compress++;
- X break;
- X
- X case '?':
- X describe();
- X exit(EX_ARGSBAD);
- X
- X }
- X }
- X
- X blocksize = blocking * RECORDSIZE;
- X}
- X
- X
- X/*
- X * Print as much help as the user's gonna get.
- X *
- X * We have to sprinkle in the KLUDGE lines because too many compilers
- X * cannot handle character strings longer than about 512 bytes. Yuk!
- X * In particular, MSDOS MSC 4.0 (and 5.0) and PDP-11 V7 Unix have this
- X * problem.
- X */
- Xvoid
- Xdescribe()
- X{
- X /* sorry, can't #ifdef AMIGA inside string */
- X fputs("\
- Xtar: valid options:\n\
- X-a set the archived bit of each file as it's added to the archive\n\
- X-b N blocking factor N (block size = Nx512 bytes)\n\
- X-B reblock as we read (for reading 4.2BSD pipes)\n\
- X-c create an archive\n\
- X-d find differences between archive and file system\n\
- X-D don't dump the contents of directories, just the directory\n\
- X", stderr); /* KLUDGE */ fputs("\
- X-f F read/write archive from file or device F (or hostname:/ForD)\n\
- X-h don't dump symbolic links; dump the files they point to\n\
- X-i ignore blocks of zeros in the archive, which normally mean EOF\n\
- X-k keep existing files, don't overwrite them from the archive\n\
- X-l stay in the local file system (like dump(8)) when creating an archive\n\
- X", stderr); /* KLUDGE */ fputs("\
- X-m don't extract file modified time\n\
- X-o write an old V7 format archive, rather than ANSI [draft 6] format\n\
- X-p do extract all protection information\n\
- X-R dump record number within archive with each message\n\
- X-s list of names to extract is sorted to match the archive\n\
- X-t list a table of contents of an archive\n\
- X", stderr); /* KLUDGE */ fputs("\
- X-T F get names to extract or create from file F\n\
- X-v verbosely list what files we process\n\
- X-x extract files from an archive\n\
- X-z or Z run the archive through compress(1)\n\
- X", stderr);
- X}
- X
- X
- X/*
- X * Set up to gather file names for tar.
- X *
- X * They can either come from stdin or from argv.
- X */
- Xname_init(argc, argv)
- X int argc;
- X char **argv;
- X{
- X
- X if (f_namefile) {
- X if (optind < argc) {
- X fprintf(stderr, "tar: too many args with -T option\n");
- X exit(EX_ARGSBAD);
- X }
- X if (!strcmp(name_file, "-")) {
- X namef = stdin;
- X } else {
- X namef = fopen(name_file, "r");
- X if (namef == NULL) {
- X fprintf(stderr, "tar: ");
- X perror(name_file);
- X exit(EX_BADFILE);
- X }
- X }
- X } else {
- X /* Get file names from argv, after options. */
- X n_argc = argc;
- X n_argv = argv;
- X }
- X}
- X
- X/*
- X * Get the next name from argv or the name file.
- X *
- X * Result is in static storage and can't be relied upon across two calls.
- X */
- Xchar *
- Xname_next()
- X{
- X static char buffer[NAMSIZ+2]; /* Holding pattern */
- X register char *p;
- X register char *q;
- X
- X if (namef == NULL) {
- X /* Names come from argv, after options */
- X if (optind < n_argc)
- X return n_argv[optind++];
- X return (char *)NULL;
- X }
- X for (;;) {
- X p = fgets(buffer, NAMSIZ+1 /*nl*/, namef);
- X if (p == NULL) return p; /* End of file */
- X q = p+strlen(p)-1; /* Find the newline */
- X if (q <= p) continue; /* Ignore empty lines */
- X *q-- = '\0'; /* Zap the newline */
- X while (q > p && *q == '/') *q-- = '\0'; /* Zap trailing /s */
- X return p;
- X }
- X /* NOTREACHED */
- X}
- X
- X
- X/*
- X * Close the name file, if any.
- X */
- Xname_close()
- X{
- X
- X if (namef != NULL && namef != stdin) fclose(namef);
- X}
- X
- X
- X/*
- X * Gather names in a list for scanning.
- X * Could hash them later if we really care.
- X *
- X * If the names are already sorted to match the archive, we just
- X * read them one by one. name_gather reads the first one, and it
- X * is called by name_match as appropriate to read the next ones.
- X * At EOF, the last name read is just left in the buffer.
- X * This option lets users of small machines extract an arbitrary
- X * number of files by doing "tar t" and editing down the list of files.
- X */
- Xname_gather()
- X{
- X register char *p;
- X static struct name namebuf[1]; /* One-name buffer */
- X
- X if (f_sorted_names) {
- X p = name_next();
- X if (p) {
- X namebuf[0].length = strlen(p);
- X if (namebuf[0].length >= sizeof namebuf[0].name) {
- X fprintf(stderr, "Argument name too long: %s\n",
- X p);
- X namebuf[0].length = (sizeof namebuf[0].name) - 1;
- X }
- X strncpy(namebuf[0].name, p, namebuf[0].length);
- X namebuf[0].name[ namebuf[0].length ] = 0;
- X namebuf[0].next = (struct name *)NULL;
- X namebuf[0].found = 0;
- X namelist = namebuf;
- X namelast = namelist;
- X }
- X return;
- X }
- X
- X /* Non sorted names -- read them all in */
- X while (NULL != (p = name_next())) {
- X addname(p);
- X }
- X}
- X
- X/*
- X * Add a name to the namelist.
- X */
- Xaddname(name)
- X char *name; /* pointer to name */
- X{
- X register int i; /* Length of string */
- X register struct name *p; /* Current struct pointer */
- X
- X i = strlen(name);
- X /*NOSTRICT*/
- X p = (struct name *)
- X malloc((unsigned)(i + sizeof(struct name) - NAMSIZ));
- X if (!p) {
- X fprintf(stderr,"tar: cannot allocate mem for namelist entry\n");
- X exit(EX_SYSTEM);
- X }
- X p->next = (struct name *)NULL;
- X p->length = i;
- X strncpy(p->name, name, i);
- X p->name[i] = '\0'; /* Null term */
- X p->found = 0;
- X p->regexp = 0; /* Assume not a regular expression */
- X p->firstch = 1; /* Assume first char is literal */
- X if (index(name, '*') || index(name, '[') || index(name, '?')) {
- X p->regexp = 1; /* No, it's a regexp */
- X if (name[0] == '*' || name[0] == '[' || name[0] == '?')
- X p->firstch = 0; /* Not even 1st char literal */
- X }
- X
- X if (namelast) namelast->next = p;
- X namelast = p;
- X if (!namelist) namelist = p;
- X}
- X
- X
- X/*
- X * Match a name from an archive, p, with a name from the namelist.
- X */
- Xname_match(p)
- X register char *p;
- X{
- X register struct name *nlp;
- X register int len;
- X
- Xagain:
- X if (0 == (nlp = namelist)) /* Empty namelist is easy */
- X return 1;
- X len = strlen(p);
- X for (; nlp != 0; nlp = nlp->next) {
- X /* If first chars don't match, quick skip */
- X if (nlp->firstch && nlp->name[0] != p[0])
- X continue;
- X
- X /* Regular expressions */
- X if (nlp->regexp) {
- X if (wildmat(p, nlp->name)) {
- X nlp->found = 1; /* Remember it matched */
- X return 1; /* We got a match */
- X }
- X continue;
- X }
- X
- X /* Plain Old Strings */
- X if (nlp->length <= len /* Archive len >= specified */
- X && (p[nlp->length] == '\0' || p[nlp->length] == '/')
- X /* Full match on file/dirname */
- X && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */
- X {
- X nlp->found = 1; /* Remember it matched */
- X return 1; /* We got a match */
- X }
- X }
- X
- X /*
- X * Filename from archive not found in namelist.
- X * If we have the whole namelist here, just return 0.
- X * Otherwise, read the next name in and compare it.
- X * If this was the last name, namelist->found will remain on.
- X * If not, we loop to compare the newly read name.
- X */
- X if (f_sorted_names && namelist->found) {
- X name_gather(); /* Read one more */
- X if (!namelist->found) goto again;
- X }
- X return 0;
- X}
- X
- X
- X/*
- X * Print the names of things in the namelist that were not matched.
- X */
- Xnames_notfound()
- X{
- X register struct name *nlp;
- X register char *p;
- X
- X for (nlp = namelist; nlp != 0; nlp = nlp->next) {
- X if (!nlp->found) {
- X fprintf(stderr, "tar: %s not found in archive\n",
- X nlp->name);
- X }
- X /*
- X * We could free() the list, but the process is about
- X * to die anyway, so save some CPU time. Amigas and
- X * other similarly broken software will need to waste
- X * the time, though.
- X */
- X#ifndef unix
- X if (!f_sorted_names)
- X free(nlp);
- X#endif
- X }
- X namelist = (struct name *)NULL;
- X namelast = (struct name *)NULL;
- X
- X if (f_sorted_names) {
- X while (0 != (p = name_next()))
- X fprintf(stderr, "tar: %s not found in archive\n", p);
- X }
- X}
- END_OF_FILE
- if test 11897 -ne `wc -c <'tar.c'`; then
- echo shar: \"'tar.c'\" unpacked with wrong size!
- fi
- # end of 'tar.c'
- fi
- echo shar: End of archive 2 \(of 5\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 5 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 5 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
- Mail comments to the moderator at <amiga-request@cs.odu.edu>.
- Post requests for sources, and general discussion to comp.sys.amiga.
-